From: Yehuda Katz Date: Fri, 30 May 2014 03:35:09 +0000 (-0700) Subject: Break up GitSource X-Git-Tag: archive/raspbian/0.35.0-2+rpi1~3^2^2^2^2^2^2^2~1032 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/success//%22http:/www.example.com/cgi/success/?a=commitdiff_plain;h=cda93d8096777bdf217ef7f69eed5cf87699e5f8;p=cargo.git Break up GitSource --- diff --git a/src/cargo/sources/git.rs b/src/cargo/sources/git.rs deleted file mode 100644 index f2bc69fdc..000000000 --- a/src/cargo/sources/git.rs +++ /dev/null @@ -1,337 +0,0 @@ -#![allow(dead_code)] - -use url::Url; -use util::{CargoResult,ProcessBuilder,io_error,human_error,process}; -use std::fmt; -use std::fmt::{Show,Formatter}; -use std::str; -use std::io::{UserDir,AllPermissions}; -use std::io::fs::{mkdir_recursive,rmdir_recursive,chmod}; -use serialize::{Encodable,Encoder}; -use core::source::Source; -use core::{NameVer,Package,Summary}; -use ops; - -#[deriving(Eq,Clone,Encodable)] -enum GitReference { - Master, - Other(String) -} - -impl GitReference { - pub fn for_str(string: S) -> GitReference { - if string.as_slice() == "master" { - Master - } else { - Other(string.as_slice().to_str()) - } - } -} - -impl Str for GitReference { - fn as_slice<'a>(&'a self) -> &'a str { - match *self { - Master => "master", - Other(ref string) => string.as_slice() - } - } -} - -impl Show for GitReference { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - self.as_slice().fmt(f) - } -} - -pub struct GitSource { - remote: GitRemote, - reference: GitReference, - db_path: Path, - checkout_path: Path, - verbose: bool -} - -impl GitSource { - pub fn new(remote: GitRemote, reference: String, db: Path, checkout: Path, verbose: bool) -> GitSource { - GitSource { remote: remote, reference: GitReference::for_str(reference), db_path: db, checkout_path: checkout, verbose: verbose } - } -} - -impl Show for GitSource { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - try!(write!(f, "git repo at {}", self.remote.url)); - - match self.reference { - Master => Ok(()), - Other(ref reference) => write!(f, " ({})", reference) - } - } -} - -impl Source for GitSource { - fn update(&self) -> CargoResult<()> { - let repo = try!(self.remote.checkout(&self.db_path)); - try!(repo.copy_to(self.reference.as_slice(), &self.checkout_path)); - - Ok(()) - } - - fn list(&self) -> CargoResult> { - let pkg = try!(read_manifest(&self.checkout_path)); - Ok(vec!(pkg.get_summary().clone())) - } - - fn download(&self, _: &[NameVer]) -> CargoResult<()> { - Ok(()) - } - - fn get(&self, packages: &[NameVer]) -> CargoResult> { - let pkg = try!(read_manifest(&self.checkout_path)); - - if packages.iter().any(|nv| pkg.is_for_name_ver(nv)) { - Ok(vec!(pkg)) - } else { - Ok(vec!()) - } - } -} - -macro_rules! git( - ($config:expr, $verbose:expr, $str:expr, $($rest:expr),*) => ( - try!(git_inherit(&$config, $verbose, format!($str, $($rest),*))) - ); - - ($config:expr, $verbose:expr, $str:expr) => ( - try!(git_inherit(&$config, $verbose, format!($str))) - ); -) - -macro_rules! git_output( - ($config:expr, $verbose:expr, $str:expr, $($rest:expr),*) => ( - try!(git_output(&$config, $verbose, format!($str, $($rest),*))) - ); - - ($config:expr, $verbose:expr, $str:expr) => ( - try!(git_output(&$config, $verbose, format!($str))) - ); -) - -macro_rules! errln( - ($($arg:tt)*) => (let _ = writeln!(::std::io::stdio::stderr(), $($arg)*)) -) - -/** - * GitRemote represents a remote repository. It gets cloned into a local GitDatabase. - */ - -#[deriving(Eq,Clone)] -pub struct GitRemote { - url: Url, - verbose: bool -} - -#[deriving(Eq,Clone,Encodable)] -struct EncodableGitRemote { - url: String -} - -impl> Encodable for GitRemote { - fn encode(&self, s: &mut S) -> Result<(), E> { - EncodableGitRemote { - url: self.url.to_str() - }.encode(s) - } -} - -/** - * GitDatabase is a local clone of a remote repository's database. Multiple GitCheckouts - * can be cloned from this GitDatabase. - */ - -#[deriving(Eq,Clone)] -pub struct GitDatabase { - remote: GitRemote, - path: Path, - verbose: bool -} - -#[deriving(Encodable)] -pub struct EncodableGitDatabase { - remote: GitRemote, - path: String -} - -impl> Encodable for GitDatabase { - fn encode(&self, s: &mut S) -> Result<(), E> { - EncodableGitDatabase { - remote: self.remote.clone(), - path: self.path.display().to_str() - }.encode(s) - } -} - -/** - * GitCheckout is a local checkout of a particular revision. Calling `clone_into` with - * a reference will resolve the reference into a revision, and return a CargoError - * if no revision for that reference was found. - */ - -pub struct GitCheckout { - database: GitDatabase, - location: Path, - reference: GitReference, - revision: String, - verbose: bool -} - -#[deriving(Encodable)] -pub struct EncodableGitCheckout { - database: GitDatabase, - location: String, - reference: String, - revision: String -} - -impl> Encodable for GitCheckout { - fn encode(&self, s: &mut S) -> Result<(), E> { - EncodableGitCheckout { - database: self.database.clone(), - location: self.location.display().to_str(), - reference: self.reference.to_str(), - revision: self.revision.to_str() - }.encode(s) - } -} - -/** - * Implementations - */ - -impl GitRemote { - pub fn new(url: Url, verbose: bool) -> GitRemote { - GitRemote { url: url, verbose: verbose } - } - - pub fn checkout(&self, into: &Path) -> CargoResult { - if into.exists() { - // TODO: If the revision we have is a rev, avoid unnecessarily fetching if we have the rev already - try!(self.fetch_into(into)); - } else { - try!(self.clone_into(into)); - } - - Ok(GitDatabase { remote: self.clone(), path: into.clone(), verbose: self.verbose }) - } - - fn fetch_into(&self, path: &Path) -> CargoResult<()> { - Ok(git!(*path, self.verbose, "fetch --force --quiet --tags {} refs/heads/*:refs/heads/*", self.url)) - } - - fn clone_into(&self, path: &Path) -> CargoResult<()> { - let dirname = Path::new(path.dirname()); - - try!(mkdir_recursive(path, UserDir).map_err(|err| - human_error(format!("Couldn't recursively create `{}`", dirname.display()), format!("path={}", dirname.display()), io_error(err)))); - - Ok(git!(dirname, self.verbose, "clone {} {} --bare --no-hardlinks --quiet", self.url, path.display())) - } -} - -impl GitDatabase { - fn get_path<'a>(&'a self) -> &'a Path { - &self.path - } - - pub fn copy_to(&self, reference: S, dest: &Path) -> CargoResult { - let verbose = self.verbose; - let checkout = try!(GitCheckout::clone_into(dest, self.clone(), GitReference::for_str(reference.as_slice()), verbose)); - - try!(checkout.fetch()); - try!(checkout.update_submodules()); - - Ok(checkout) - } - - pub fn rev_for(&self, reference: S) -> CargoResult { - Ok(git_output!(self.path, self.verbose, "rev-parse {}", reference.as_slice())) - } - -} - -impl GitCheckout { - fn clone_into(into: &Path, database: GitDatabase, reference: GitReference, verbose: bool) -> CargoResult { - let revision = try!(database.rev_for(reference.as_slice())); - let checkout = GitCheckout { location: into.clone(), database: database, reference: reference, revision: revision, verbose: verbose }; - - // If the git checkout already exists, we don't need to clone it again - if !checkout.location.join(".git").exists() { - try!(checkout.clone_repo()); - } - - Ok(checkout) - } - - fn get_source<'a>(&'a self) -> &'a Path { - self.database.get_path() - } - - fn clone_repo(&self) -> CargoResult<()> { - let dirname = Path::new(self.location.dirname()); - - try!(mkdir_recursive(&dirname, UserDir).map_err(|e| - human_error(format!("Couldn't mkdir {}", Path::new(self.location.dirname()).display()), None::<&str>, io_error(e)))); - - if self.location.exists() { - try!(rmdir_recursive(&self.location).map_err(|e| - human_error(format!("Couldn't rmdir {}", Path::new(&self.location).display()), None::<&str>, io_error(e)))); - } - - git!(dirname, self.verbose, "clone --no-checkout --quiet {} {}", self.get_source().display(), self.location.display()); - try!(chmod(&self.location, AllPermissions).map_err(io_error)); - - Ok(()) - } - - fn fetch(&self) -> CargoResult<()> { - git!(self.location, self.verbose, "fetch --force --quiet --tags {}", self.get_source().display()); - try!(self.reset(self.revision.as_slice())); - Ok(()) - } - - fn reset(&self, revision: T) -> CargoResult<()> { - Ok(git!(self.location, self.verbose, "reset -q --hard {}", revision)) - } - - fn update_submodules(&self) -> CargoResult<()> { - Ok(git!(self.location, self.verbose, "submodule update --init --recursive --quiet")) - } -} - -fn git(path: &Path, verbose: bool, str: &str) -> ProcessBuilder { - if verbose { - errln!("Executing git {} @ {}", str, path.display()); - } - - process("git").args(str.split(' ').collect::>().as_slice()).cwd(path.clone()) -} - -fn git_inherit(path: &Path, verbose: bool, str: String) -> CargoResult<()> { - git(path, verbose, str.as_slice()).exec().map_err(|err| - human_error(format!("Executing `git {}` failed: {}", str, err), None::<&str>, err)) -} - -fn git_output(path: &Path, verbose: bool, str: String) -> CargoResult { - let output = try!(git(path, verbose, str.as_slice()).exec_with_output().map_err(|err| - human_error(format!("Executing `git {}` failed", str), None::<&str>, err))); - - Ok(to_str(output.output.as_slice()).as_slice().trim_right().to_str()) -} - -fn to_str(vec: &[u8]) -> String { - str::from_utf8_lossy(vec).to_str() -} - -fn read_manifest(path: &Path) -> CargoResult { - let joined = path.join("Cargo.toml"); - ops::read_manifest(joined.as_str().unwrap()) -} diff --git a/src/cargo/sources/git/mod.rs b/src/cargo/sources/git/mod.rs new file mode 100644 index 000000000..f44594a28 --- /dev/null +++ b/src/cargo/sources/git/mod.rs @@ -0,0 +1,4 @@ +pub use self::utils::{GitRemote,GitDatabase,GitCheckout}; +pub use self::source::{GitSource}; +mod utils; +mod source; diff --git a/src/cargo/sources/git/source.rs b/src/cargo/sources/git/source.rs new file mode 100644 index 000000000..f1c5db2cc --- /dev/null +++ b/src/cargo/sources/git/source.rs @@ -0,0 +1,65 @@ +use ops; +use core::source::Source; +use core::{NameVer,Package,Summary}; +use util::CargoResult; +use sources::git::utils::{GitReference,GitRemote,Master,Other}; +use std::fmt; +use std::fmt::{Show,Formatter}; + +pub struct GitSource { + remote: GitRemote, + reference: GitReference, + db_path: Path, + checkout_path: Path, + verbose: bool +} + +impl GitSource { + pub fn new(remote: GitRemote, reference: String, db: Path, checkout: Path, verbose: bool) -> GitSource { + GitSource { remote: remote, reference: GitReference::for_str(reference), db_path: db, checkout_path: checkout, verbose: verbose } + } +} + +impl Show for GitSource { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + try!(write!(f, "git repo at {}", self.remote.get_url())); + + match self.reference { + Master => Ok(()), + Other(ref reference) => write!(f, " ({})", reference) + } + } +} + +impl Source for GitSource { + fn update(&self) -> CargoResult<()> { + let repo = try!(self.remote.checkout(&self.db_path)); + try!(repo.copy_to(self.reference.as_slice(), &self.checkout_path)); + + Ok(()) + } + + fn list(&self) -> CargoResult> { + let pkg = try!(read_manifest(&self.checkout_path)); + Ok(vec!(pkg.get_summary().clone())) + } + + fn download(&self, _: &[NameVer]) -> CargoResult<()> { + Ok(()) + } + + fn get(&self, packages: &[NameVer]) -> CargoResult> { + let pkg = try!(read_manifest(&self.checkout_path)); + + if packages.iter().any(|nv| pkg.is_for_name_ver(nv)) { + Ok(vec!(pkg)) + } else { + Ok(vec!()) + } + } +} + +fn read_manifest(path: &Path) -> CargoResult { + let joined = path.join("Cargo.toml"); + ops::read_manifest(joined.as_str().unwrap()) +} diff --git a/src/cargo/sources/git/utils.rs b/src/cargo/sources/git/utils.rs new file mode 100644 index 000000000..50a3c7c25 --- /dev/null +++ b/src/cargo/sources/git/utils.rs @@ -0,0 +1,279 @@ +use url::Url; +use util::{CargoResult,ProcessBuilder,io_error,human_error,process}; +use std::fmt; +use std::fmt::{Show,Formatter}; +use std::str; +use std::io::{UserDir,AllPermissions}; +use std::io::fs::{mkdir_recursive,rmdir_recursive,chmod}; +use serialize::{Encodable,Encoder}; + +#[deriving(Eq,Clone,Encodable)] +pub enum GitReference { + Master, + Other(String) +} + +impl GitReference { + pub fn for_str(string: S) -> GitReference { + if string.as_slice() == "master" { + Master + } else { + Other(string.as_slice().to_str()) + } + } +} + +impl Str for GitReference { + fn as_slice<'a>(&'a self) -> &'a str { + match *self { + Master => "master", + Other(ref string) => string.as_slice() + } + } +} + +impl Show for GitReference { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + self.as_slice().fmt(f) + } +} + + +macro_rules! git( + ($config:expr, $verbose:expr, $str:expr, $($rest:expr),*) => ( + try!(git_inherit(&$config, $verbose, format!($str, $($rest),*))) + ); + + ($config:expr, $verbose:expr, $str:expr) => ( + try!(git_inherit(&$config, $verbose, format!($str))) + ); +) + +macro_rules! git_output( + ($config:expr, $verbose:expr, $str:expr, $($rest:expr),*) => ( + try!(git_output(&$config, $verbose, format!($str, $($rest),*))) + ); + + ($config:expr, $verbose:expr, $str:expr) => ( + try!(git_output(&$config, $verbose, format!($str))) + ); +) + +macro_rules! errln( + ($($arg:tt)*) => (let _ = writeln!(::std::io::stdio::stderr(), $($arg)*)) +) + +/** + * GitRemote represents a remote repository. It gets cloned into a local GitDatabase. + */ + +#[deriving(Eq,Clone)] +pub struct GitRemote { + url: Url, + verbose: bool +} + +#[deriving(Eq,Clone,Encodable)] +struct EncodableGitRemote { + url: String +} + +impl> Encodable for GitRemote { + fn encode(&self, s: &mut S) -> Result<(), E> { + EncodableGitRemote { + url: self.url.to_str() + }.encode(s) + } +} + +/** + * GitDatabase is a local clone of a remote repository's database. Multiple GitCheckouts + * can be cloned from this GitDatabase. + */ + +#[deriving(Eq,Clone)] +pub struct GitDatabase { + remote: GitRemote, + path: Path, + verbose: bool +} + +#[deriving(Encodable)] +pub struct EncodableGitDatabase { + remote: GitRemote, + path: String +} + +impl> Encodable for GitDatabase { + fn encode(&self, s: &mut S) -> Result<(), E> { + EncodableGitDatabase { + remote: self.remote.clone(), + path: self.path.display().to_str() + }.encode(s) + } +} + +/** + * GitCheckout is a local checkout of a particular revision. Calling `clone_into` with + * a reference will resolve the reference into a revision, and return a CargoError + * if no revision for that reference was found. + */ + +pub struct GitCheckout { + database: GitDatabase, + location: Path, + reference: GitReference, + revision: String, + verbose: bool +} + +#[deriving(Encodable)] +pub struct EncodableGitCheckout { + database: GitDatabase, + location: String, + reference: String, + revision: String +} + +impl> Encodable for GitCheckout { + fn encode(&self, s: &mut S) -> Result<(), E> { + EncodableGitCheckout { + database: self.database.clone(), + location: self.location.display().to_str(), + reference: self.reference.to_str(), + revision: self.revision.to_str() + }.encode(s) + } +} + +/** + * Implementations + */ + +impl GitRemote { + pub fn new(url: Url, verbose: bool) -> GitRemote { + GitRemote { url: url, verbose: verbose } + } + + pub fn get_url<'a>(&'a self) -> &'a Url { + &self.url + } + + pub fn checkout(&self, into: &Path) -> CargoResult { + if into.exists() { + try!(self.fetch_into(into)); + } else { + try!(self.clone_into(into)); + } + + Ok(GitDatabase { remote: self.clone(), path: into.clone(), verbose: self.verbose }) + } + + fn fetch_into(&self, path: &Path) -> CargoResult<()> { + Ok(git!(*path, self.verbose, "fetch --force --quiet --tags {} refs/heads/*:refs/heads/*", self.url)) + } + + fn clone_into(&self, path: &Path) -> CargoResult<()> { + let dirname = Path::new(path.dirname()); + + try!(mkdir_recursive(path, UserDir).map_err(|err| + human_error(format!("Couldn't recursively create `{}`", dirname.display()), format!("path={}", dirname.display()), io_error(err)))); + + Ok(git!(dirname, self.verbose, "clone {} {} --bare --no-hardlinks --quiet", self.url, path.display())) + } +} + +impl GitDatabase { + fn get_path<'a>(&'a self) -> &'a Path { + &self.path + } + + pub fn copy_to(&self, reference: S, dest: &Path) -> CargoResult { + let verbose = self.verbose; + let checkout = try!(GitCheckout::clone_into(dest, self.clone(), GitReference::for_str(reference.as_slice()), verbose)); + + try!(checkout.fetch()); + try!(checkout.update_submodules()); + + Ok(checkout) + } + + pub fn rev_for(&self, reference: S) -> CargoResult { + Ok(git_output!(self.path, self.verbose, "rev-parse {}", reference.as_slice())) + } + +} + +impl GitCheckout { + fn clone_into(into: &Path, database: GitDatabase, reference: GitReference, verbose: bool) -> CargoResult { + let revision = try!(database.rev_for(reference.as_slice())); + let checkout = GitCheckout { location: into.clone(), database: database, reference: reference, revision: revision, verbose: verbose }; + + // If the git checkout already exists, we don't need to clone it again + if !checkout.location.join(".git").exists() { + try!(checkout.clone_repo()); + } + + Ok(checkout) + } + + fn get_source<'a>(&'a self) -> &'a Path { + self.database.get_path() + } + + fn clone_repo(&self) -> CargoResult<()> { + let dirname = Path::new(self.location.dirname()); + + try!(mkdir_recursive(&dirname, UserDir).map_err(|e| + human_error(format!("Couldn't mkdir {}", Path::new(self.location.dirname()).display()), None::<&str>, io_error(e)))); + + if self.location.exists() { + try!(rmdir_recursive(&self.location).map_err(|e| + human_error(format!("Couldn't rmdir {}", Path::new(&self.location).display()), None::<&str>, io_error(e)))); + } + + git!(dirname, self.verbose, "clone --no-checkout --quiet {} {}", self.get_source().display(), self.location.display()); + try!(chmod(&self.location, AllPermissions).map_err(io_error)); + + Ok(()) + } + + fn fetch(&self) -> CargoResult<()> { + git!(self.location, self.verbose, "fetch --force --quiet --tags {}", self.get_source().display()); + try!(self.reset(self.revision.as_slice())); + Ok(()) + } + + fn reset(&self, revision: T) -> CargoResult<()> { + Ok(git!(self.location, self.verbose, "reset -q --hard {}", revision)) + } + + fn update_submodules(&self) -> CargoResult<()> { + Ok(git!(self.location, self.verbose, "submodule update --init --recursive --quiet")) + } +} + +fn git(path: &Path, verbose: bool, str: &str) -> ProcessBuilder { + if verbose { + errln!("Executing git {} @ {}", str, path.display()); + } + + process("git").args(str.split(' ').collect::>().as_slice()).cwd(path.clone()) +} + +fn git_inherit(path: &Path, verbose: bool, str: String) -> CargoResult<()> { + git(path, verbose, str.as_slice()).exec().map_err(|err| + human_error(format!("Executing `git {}` failed: {}", str, err), None::<&str>, err)) +} + +fn git_output(path: &Path, verbose: bool, str: String) -> CargoResult { + let output = try!(git(path, verbose, str.as_slice()).exec_with_output().map_err(|err| + human_error(format!("Executing `git {}` failed", str), None::<&str>, err))); + + Ok(to_str(output.output.as_slice()).as_slice().trim_right().to_str()) +} + +fn to_str(vec: &[u8]) -> String { + str::from_utf8_lossy(vec).to_str() +} +